#include <QStringList>
#include "jsbackend.h"
#include "../../errorlog.h"
#include "../../parser.h"
#include "../../template.h"
#include "../../body.h"
#include "../../htmlelement.h"
#include "../../htmlattribute.h"
#include "../../htmlattributelist.h"
#include "../../htmlif.h"
#include "../../htmlforeach.h"
#include "../../textnode.h"
#include "../../constant.h"
#include "../../var.h"
#include "../../expression.h"
#include "../../templatecall.h"
#include "../../parameter.h"
#include "../../parameterlist.h"
#include "../../operator.h"
#include "../../function.h"
#include "../../component.h"
#include "../../property.h"
#include "../../componentcall.h"
#include "../../memberevent.h"
#include "../../getopts.h"
#include "../../membertemplate.h"

JSBackend::JSBackend(const QOptions* options)
        : m_mainOutDecl( new QString() ), m_mainOutDef( new QString() ), m_identCount(0), m_options(options)
{
    QString file = options->nonOptionValues()[0];
    if ( file.endsWith(".wala") )
        file = file.mid(0, file.length() - 5 ) + ".js";
    else
        file += ".js";

    m_fileOut.setFileName(file);
    if ( !m_fileOut.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
    {
        ErrorLog::error( YYLTYPE(), "Could not write to " + m_fileOut.fileName() );
        return;
    }

    m_out.setDevice( &m_fileOut );

    m_mainOutDecl << "function main()" << endl << "{" << endl;

    if ( options->option(Cmd_Html).occurrence() )
    {
        QFile html( options->option(Cmd_Html).value() );
        if ( !html.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
        {
            ErrorLog::error( YYLTYPE(), "Could not write to " + html.fileName() );
            return;
        }

        QTextStream out(&html);
        out << "<html>" << endl;
        out << "<head>" << endl;
        out << "<title>Generated HTML file</title>" << endl;
        out << "<script src=\"json.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"utils.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"wala.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"template.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"rpc.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"common.pbjson.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"waveclient-rpc.pbjson.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"webclient.pbjson.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"jsot.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"wave.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"editor.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"domiterator.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"" << m_fileOut.fileName() << "\" type=\"text/javascript\"></script>" << endl;
        out << "<style type=\"text/css\">" << endl;
        out << "body { font-family:aria,sans-serif; }" << endl;
        out << ".jsot_caret { background-color:red; color:white; display:inline; font-size:9pt; position:relative; top:-2px }" << endl;
        out << ".thread { border: 1px solid green; margin: 2px }" << endl;
        out << ".blip { border: 1px solid red; margin: 2px }" << endl;
        out << ".digest { border: 1px solid blue; margin: 2px }" << endl;
        out << "</style>" << endl;
        out << "</head>" << endl;
        out << "<body id=\"body\" onload=\"main()\">" << endl;
        out << "</body>" << endl;
        out << "</html>" << endl;

        out.flush();
        html.close();
    }
    if ( options->option(Cmd_Manifest).occurrence() )
    {
        if ( options->option(Cmd_UrlPrefix).value().isEmpty() )
        {
            ErrorLog::error( YYLTYPE(), "You must set the --urlprefix parameter as well.");
            return;
        }
        QString prefix = options->option(Cmd_UrlPrefix).value();

        QFile gadget( options->option(Cmd_Manifest).value() );
        if ( !gadget.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
        {
            ErrorLog::error( YYLTYPE(), "Could not write to " + gadget.fileName() );
            return;
        }

        QTextStream out(&gadget);
        out << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << endl;
        out << "<Module>" << endl;
        out << "<ModulePrefs title=\"Generated Gadget\" height=\"800\">" << endl;
        out << "<Require feature=\"wave\" />" << endl;
        out << "<Require feature=\"dynamic-height\"/>" << endl;
        out << "</ModulePrefs>" << endl;
        out << "<Content type=\"html\">" << endl;
        out << "<![CDATA[" << endl;
        out << "<div id=\"body\"></div>" << endl;
        out << "<script src=\"" << prefix << "utils.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"" << prefix << "wala.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script src=\"" << prefix << "template.js\" type=\"text/javascript\"></script>" << endl;
        out << "<script type=\"text/javascript\" src=\"" << prefix << m_fileOut.fileName() << "\"></script>" << endl;
        out << "<script src=\"" << prefix << "gadget.js\" type=\"text/javascript\"></script>" << endl;
        out << "]]>" << endl;
        out << "</Content>" << endl;
        out << "</Module>" << endl;
        out.flush();
        gadget.close();
    }
}

void JSBackend::run()
{
    Parser* parser =  Parser::self();

    foreach( Template* t, parser->templates() )
    {
        QString templateIdent = nextIdent();
        t->data()["ident"] = templateIdent;
    }

    foreach( Component* c, parser->components() )
    {
        c->data()["ident"] = c->name();
    }

    foreach( Var* v, parser->variables() )
    {
        v->data()["ident"] = "wala.getVar(" + stringify(v->name()) + ")";
    }

    foreach( Component* c, parser->components() )
    {
        generateComponent(c);
    }

    foreach( Template* t, parser->templates() )
    {
        generateTemplateBody( t );
    }

    foreach( UserFunction* f, parser->userFunctions() )
    {
        generateUserFunction( f );
    }

    foreach( Var* v, parser->variables() )
    {
        generateVarInitialization( v );
    }
}

void JSBackend::generateComponent(Component* c)
{
    QString cIdent = c->data()["ident"];

    foreach( Template* t, c->templates() )
    {
        QString templateIdent = nextIdent();
        t->data()["ident"] = templateIdent;
    }

    //
    // Generate the constructor
    //

    m_out << "function " << cIdent << "()" << endl << "{" << endl;
    // Expression constructors require this to register themselves
    m_out << "this.__expressions = [];" << endl;
    m_out << "var self = this;" << endl;
    // Create an event instance for each MemberEvent
    foreach( MemberEvent* e, c->events() )
    {
        m_out << "this." << e->name() << "_event = new wala.Event(this);" << endl;
    }
    // Create an expression for each property that reflects the property value
    foreach( Property* p, c->properties() )
    {
        if ( p->readonly() )
            m_out << "this.expr_" << p->name() << " = new wala.Expression(this, function() { return self.val_" << p->name() << ";});" << endl;
        else
        {
            QString empty = "null";
            if ( p->type().isList() )
                empty = "[]";
            m_out << "this.expr_" << p->name() << " = new wala.Expression(this, function(){if(self.val_" << p->name() << ")return self.val_" << p->name() << ".evaluate();return " << empty << ";});" << endl;
        }
        if ( p->initExpression() )
        {
            m_out << "this.set_" << p->name() << "(";
            QTextStream out( new QString() );
            generateExpression( p->initExpression(), out );
            m_out << *(out.string()) << ");" << endl;
        }
        // Does the property have a user-defined update script? -> Call it when the property value changes
        if ( !p->updateScript().isNull() )
        {
            m_out << "this.expr_" << p->name() << ".onChange.push( function() { self.update_" << p->name() << "(); });" << endl;
        }
    }
    m_out << "}" << endl << endl;

    //
    // Generate the getValueAndListen function
    //

    m_out << cIdent << ".prototype.getValueAndListen = function(name, expr)" << endl << "{" << endl;
    foreach( Property* p, c->properties() )
    {
        m_out << "if ( name == " << stringify(p->name()) << ")" << endl << "{" << endl;
        m_out << "var e = this.expr_" << p->name() << ";" << endl;
        m_out << "e.addChildExpression(expr);" << endl;
        m_out << "return e.evaluate();" << endl;
        m_out << "}" << endl;
    }
    foreach( MemberTemplate* m, c->memberTemplates() )
    {
        m_out << "if ( name == " << stringify(m->name()) << ")" << endl << "{" << endl;
        m_out << "var e = this.expr_" << m->name() << ";" << endl;
        m_out << "e.addChildExpression(expr);" << endl;
        m_out << "return e.evaluate();" << endl;
        m_out << "}" << endl;
    }
    m_out << "return null;" << endl;
    m_out << "}" << endl << endl;

    //
    // Generate the user-defined init function
    //
    m_out << cIdent << ".prototype.__ctor = function()" << endl << "{" << endl;
    m_out << c->constructor()->body();
    m_out << "};" << endl << endl;

    //
    // Generate the (partly user defined) destructor function
    //
    m_out << cIdent << ".prototype.__dtor = function()" << endl << "{" << endl;
    if ( c->destructor() )
    {
        // Wrap the user defined destructor code, because it could contain a return statement
        m_out << "(function() {" << endl;
        m_out << c->destructor()->body();
        m_out << "})();" << endl;
    }
    m_out << "for( var i = 0; i < this.__expressions.length; ++i ) this.__expressions[i].dtor();" << endl;
    m_out << "};" << endl << endl;

    foreach( MemberFunction* f, c->memberFunctions() )
    {
        generateMemberFunction(f);
    }

    foreach( Property* p, c->properties() )
    {
        generateProperty(p);
    }

    foreach( MemberTemplate* m, c->memberTemplates() )
    {
        generateMemberTemplate(m);
    }

    foreach( Template* t, c->templates() )
    {
        generateTemplateBody(t);

        m_out << cIdent << ".prototype." << t->name() << " = function()" << endl << "{" << endl;
        m_out << "var tmpl = " << t->data()["ident"] << ".createInstance([], null, this);" << endl;
        m_out << "return tmpl.domNodes;" << endl;
        m_out << "};" << endl << endl;
    }
}

void JSBackend::generateEvent(MemberEvent* e)
{
    Component* c = e->component();
    Q_ASSERT(c);
    QString cIdent = c->data()["ident"];

    m_out << cIdent << ".prototype." << e->name() << " = function()" << endl << "{" << endl;
    m_out << "this." << e->name() << "_event.emit();" << endl;
    m_out << "};" << endl << endl;
}

void JSBackend::generateProperty(Property* p)
{
    Component* c = p->component();
    Q_ASSERT(c);
    QString cIdent = c->data()["ident"];
    Q_ASSERT(!cIdent.isNull());

    if ( p->readonly() )
    {
        m_out << cIdent << ".prototype.get_" << p->name() << " = function()" << endl << "{" << endl;
        m_out << "return this.val_" << p->name() << ";" << endl;
        m_out << "};" << endl << endl;

        m_out << cIdent << ".prototype.set_" << p->name() << " = function(value)" << endl << "{" << endl;
        m_out << "this.val_" << p->name() << " = value;" << endl;
        // TODO: Compare the two values for equality before flagging the property as dirty
        m_out << "if ( this.expr_" << p->name() << " ) this.expr_" << p->name() << ".setDirty();" << endl;
        m_out << "};" << endl << endl;
    }
    else
    {
        m_out << cIdent << ".prototype.get_" << p->name() << " = function()" << endl << "{" << endl;
        m_out << "return this.expr_" << p->name() << ".evaluate();" << endl;
        m_out << "};" << endl << endl;

        m_out << cIdent << ".prototype.set_" << p->name() << " = function(expr)" << endl << "{" << endl;
        m_out << "if ( expr instanceof wala.Expression )" << endl << "{" << endl;
        m_out << "this.val_" << p->name() << " = expr;" << endl;
        m_out << "expr.addChildExpression(this.expr_" << p->name() << ");" << endl;
        m_out << "}" << endl << "else" << endl << "{" << endl;
        m_out << "this.expr_" << p->name() << ".evaluate = function() { return expr; };" << endl;
        m_out << "}" << endl;
        m_out << "this.expr_" << p->name() << ".setDirty();" << endl;
        m_out << "};" << endl << endl;
    }

    if ( !p->updateScript().isNull() )
    {
        m_out << cIdent << ".prototype.update_" << p->name() << " = function()" << endl << "{" << endl;
        m_out << p->updateScript() << endl;
        m_out << "};" << endl << endl;
    }
}

void JSBackend::generateMemberTemplate(MemberTemplate* p)
{
    Component* c = p->component();
    Q_ASSERT(c);
    QString cIdent = c->data()["ident"];
    Q_ASSERT(!cIdent.isNull());

    m_out << cIdent << ".prototype.get_" << p->name() << " = function()" << endl << "{" << endl;
    m_out << "return this.expr_" << p->name() << endl;
    m_out << "};" << endl << endl;

    m_out << cIdent << ".prototype.set_" << p->name() << " = function(expr)" << endl << "{" << endl;
    m_out << "this.expr_" << p->name() << " = expr;" << endl;
    m_out << "};" << endl << endl;
}

void JSBackend::generateMemberFunction(MemberFunction *f)
{
    Component* c = f->component();
    Q_ASSERT(c);
    QString cIdent = c->data()["ident"];
    Q_ASSERT(!cIdent.isNull());
    QString fIdent = f->jsName();
    f->data()["ident"] = fIdent;

    m_out << cIdent << ".prototype." << fIdent << " = function(";
    bool first = true;
    foreach( Parameter* p, f->parameterList()->parameters() )
    {
        if ( !first )
            m_out << ",";
        m_out << p->jsName();
        first = false;
    }

    m_out << ")" << endl << "{" << endl << f->body();
    m_out << "};" << endl << endl;
}

void JSBackend::generateUserFunction(UserFunction* f)
{
    m_out << "function " << f->jsName() << "(";
    bool first = true;
    foreach( Parameter* p, f->parameterList()->parameters() )
    {
        if ( !first )
            m_out << ",";
        m_out << p->jsName();
        first = false;
    }

    m_out << ")" << endl << "{" << endl << f->body();
    m_out << "}" << endl << endl;
}

void JSBackend::generateVarInitialization(Var* v)
{
    QTextStream expr( new QString() );
    generateExpression( v->initialValue(), expr );
    if ( v->isConstant() )
    {
        m_mainOutDecl << "wala.setVar(" << stringify(v->name()) << "," << *(expr.string()) << ");" << endl;
    }
    else
    {
        m_mainOutDecl << "wala.setVar(" << stringify(v->name()) << "," << "new wala.Expression(null, function() { return " << *(expr.string()) << "; }, " << parametersUsedInExpression(v->initialValue()) << " ) );" << endl;
    }
}

void JSBackend::generateTemplateBody(Template* t)
{
    QString templateIdent = t->data()["ident"];
    QString funcIdent = nextIdent();
    QString destructorIdent = nextIdent();
    QString allNodesIdent = nextIdent();

    m_mainOutDecl << templateIdent << " = new wala.TemplateFactory( " << funcIdent << ", " << destructorIdent << ", " << allNodesIdent << " );" << endl;

    // Generate the constructor for the template
    QTextStream out( new QString() );
    out << "function " << funcIdent << "(t)" << endl << "{" << endl;

    // A unique identifier for each parameter
    int i = 0;
    foreach( Parameter* p, t->parameterList()->parameters() )
    {
        p->data()["ident"] = QString("t.context[%1]").arg(i);
        i++;
    }

    // Generate the HTML etc.
    generateHtmlBody_Pass1(t->body(), out);
    generateHtmlBody_Pass2(t->body(), out, "t.domNodes.push(%1);");
    out << "}" << endl << endl;

    out << "function " << destructorIdent << "(t)" << endl << "{" << endl;
//    out << "var next = null;" << endl;
    generateHtmlBody_Pass3(t->body(), out);
//    out << "return next;" << endl;
    out << "}" << endl << endl;

    out << "function " << allNodesIdent << "(t, nodes)" << endl << "{" << endl;
    generateHtmlBody_Pass4(t->body(), out);
    out << "}" << endl << endl;

    m_out << *(out.string());
}

void JSBackend::generateHtmlBody_Pass1(Body* body, QTextStream& out)
{
    Node* p = body->firstChild();
    while( p )
    {
        if ( dynamic_cast<HtmlElement*>(p) )
        {
            HtmlElement* h = dynamic_cast<HtmlElement*>(p);
            generateHtmlElement_Pass1(h, out);
        }
        else if ( dynamic_cast<TextNode*>(p) )
        {
            TextNode* t = dynamic_cast<TextNode*>(p);
            QString id = nextIdent();
            t->data()["ident"] = id;
            QString text = t->text();
            if ( text.trimmed().isEmpty() )
                text = " ";
            out << "t." << id << " = document.createTextNode(" << stringify(text) << ");" << endl;
        }
        else if ( dynamic_cast<ComponentCall*>(p) )
        {
            ComponentCall* c = dynamic_cast<ComponentCall*>(p);
            if ( c->data()["ident"].isNull() )
                c->data()["ident"] = nextIdent();
            QString idCall = c->data()["ident"];

            out << "t." << idCall << " = new " << c->component()->data()["ident"] << "();" << endl;
        }
        p = p->nextSibling();
    }
}

void JSBackend::generateHtmlBody_Pass2(Body* body, QTextStream& out, QString finalStatement)
{
    Node* p = body->firstChild();
    while( p )
    {
        HtmlElement* h = dynamic_cast<HtmlElement*>(p);
        if ( h )
        {
            generateHtmlElement_Pass2(h,out);
            QString id = h->data()["ident"];
            out << finalStatement.arg( "t." + id ) << endl;
        }
        else if ( dynamic_cast<TextNode*>(p) )
        {
            TextNode* t = dynamic_cast<TextNode*>(p);
            QString id = t->data()["ident"];
            out << finalStatement.arg( "t." + id ) << endl;
        }
        else if ( dynamic_cast<HtmlIf*>(p) )
        {
            HtmlIf* f = dynamic_cast<HtmlIf*>(p);
            QString idIf = nextIdent();
            f->data()["ident"] = idIf;
            out << "t." << idIf << " = { };" << endl;
            out << "t." << idIf << ".func = function() {";
            HtmlIf* f2 = f;
            int i = 0;
            while( true )
            {
                if ( !f2 )
                {
                    out << "t.processIf(t." << idIf << ", null, null);";
                    break;
                }
                transformIf(f2);
                if ( f2->expr() )
                    out << "if ( t." << idIf << ".expr" << i << ".evaluate() ) { t.processIf(t." << idIf << ", t." << idIf << ".template" << i << ", t." << idIf << ".context" << i << "); return; }";
                else
                {
                    out << "t.processIf(t." << idIf << ", t." << idIf << ".template" << i << ", t." << idIf << ".context" << i << ");";
                    break;
                }
                f2 = f2->elseClause();
                i++;
            }
            out << "};" << endl;

            f2 = f;
            i = 0;
            while(f2)
            {
                out << "t." << idIf << ".context" << i << " = [";
                bool first = true;
                foreach( Parameter* p, f2->bodyTemplate()->parameterList()->parameters() )
                {
                    Node* passed = f->nspace()->resolve(p->name());
                    Q_ASSERT(passed);
                    if ( !first )
                        out << ",";
                    out << passed->data()["ident"];
                    first = false;
                }
                out << "];" << endl;
                out << "t." << idIf << ".template" << i << " = " << f2->bodyTemplate()->data()["ident"] << ";" << endl;
                if ( !f2->expr() )
                    break;
                out << "t." << idIf << ".expr" << i << " = new wala.Expression(t, function() { return ";
                generateExpression( f2->expr(), out );
                out << "; }, " << parametersUsedInExpression(f2->expr()) << " );" << endl;
                out << "t." << idIf << ".expr" << i << ".onChange.push(t." << idIf << ".func);" << endl;
                f2 = f2->elseClause();
                i++;
            }

            out << "t." << idIf << ".func();" << endl;
            out << "for( var i = 0; i < t." << idIf << ".nodes.length; ++i ) " << finalStatement.arg("t." + idIf + ".nodes[i]") << endl;
        }
        else if ( dynamic_cast<HtmlForeach*>(p) )
        {
            HtmlForeach* f = dynamic_cast<HtmlForeach*>(p);

            // Generate an intermediate template and attach the body to it.
            // The body of the foreach loop is treated as a separate template
            ParameterList* params = new ParameterList( f->location() );
            Parameter* var = new Parameter( f->variable()->name(), f->variable()->type(), f->variable()->location() );
            var->data()["noexpression"] = "true";
            params->appendChild( var );
            Parameter* index = 0;
            if ( f->index() )
                index = new Parameter( f->index()->name(), f->index()->type(), f->index()->location() );
            else
                index = new Parameter( "_dummy_", Type(Type::Scalar), YYLTYPE() );
            index->setIsIndex();
            params->appendChild(index);
            index->data()["noexpression"] = "true";
            QSet<Parameter*> paramsDecl = parametersDeclared(f->body());
            QList<Parameter*> paramsPassed;
            foreach( Parameter* p, parametersUsed(f->body()) )
            {
                if ( !paramsDecl.contains(p) && f->variable() != p && f->index() != p )
                {
                    paramsPassed.append(p);
                    Parameter* p2 = new Parameter( p->name(), p->type(), p->location() );
                    if ( !p->data()["noexpression"].isNull() )
                        p2->data()["noexpression"] = p->data()["noexpression"];
                    params->appendChild( p2 );
                }
            }
            Template* t = new Template( nextIdent(), params, f->body(), f->location() );
            t->data()["ident"] = nextIdent();
            f->setBodyTemplate(t);
            t->resolveAll();
            generateTemplateBody(t);

            QString idForeach = nextIdent();
            f->data()["ident"] = idForeach;
            out << "t." << idForeach << " = {};" << endl;

            // Create the expression in which we want to iterate
            out << "t." << idForeach << ".expr = new wala.Expression(t, function() { return ";
            generateExpression( f->expr(), out );
            out << "; }, " << parametersUsedInExpression(f->expr()) << " );" << endl;

            // Create the function that is invoked when the expression changes
            out << "t." << idForeach << ".template = " << t->data()["ident"] << ";" << endl;
            out << "t." << idForeach << ".templates = [];" << endl;
            out << "t." << idForeach << ".list = [];" << endl;
            out << "t." << idForeach << ".context = [";
            bool first = true;
            for( int i = 0; i < paramsPassed.count(); ++i )
            {
                if ( !first )
                    out << ",";
                out << paramsPassed[i]->data()["ident"];
                first = false;
            }
            out << "];" << endl;
            out << "t." << idForeach << ".func = function() { t.processForeach( t." << idForeach << ", " << (f->hasIndex() ? "true" : "false") << " ); };" << endl;
            out << "t." << idForeach << ".expr.onChange.push( t." << idForeach << ".func );" << endl;
            out << "t." << idForeach << ".func.call(t." << idForeach << ".expr);" << endl;
            out << "for( var i = 0; i < t." << idForeach << ".nodes.length; ++i ) " << finalStatement.arg("t." + idForeach + ".nodes[i]") << endl;

            // Repatronize the body.
            f->appendChild( t->body() );
            delete t;
        }
        else if ( dynamic_cast<TemplateCall*>(p) )
        {
            TemplateCall* c = dynamic_cast<TemplateCall*>(p);
            QString idInstance = nextIdent();
            c->data()["ident"] = idInstance;
            if ( c->resolvedTemplate() )
            {
                Template* t = c->resolvedTemplate();
                out << "t." << idInstance << " = " << t->data()["ident"] << ".createInstance( [";
                bool first = true;
                foreach( Expression* e, c->arguments()->expressions() )
                {
                    if ( !first )
                        out << ",";
                    out << "new wala.Expression(t, function() { return ";
                    generateExpression( e, out );
                    out << "; }, " << parametersUsedInExpression(e) << " )";
                    first = false;
                }
                out << "], t );" << endl;
                out << "for( var i = 0; i < t." << idInstance << ".domNodes.length; ++i ) " << finalStatement.arg( "t." + idInstance + ".domNodes[i]") << endl;
            }
            else if ( c->resolvedMemberTemplate() )
            {
                MemberTemplate* t = c->resolvedMemberTemplate();
                QString tmp = nextIdent();
                out << "var " << tmp << " = " << "t.component.get_" << t->name() << "();" << endl;
                out << "t." << idInstance << " = " << tmp << ".evaluate().createInstance( [";
                bool first = true;
                foreach( Expression* e, c->arguments()->expressions() )
                {
                    if ( !first )
                        out << ",";
                    out << "new wala.Expression(t, function() { return ";
                    generateExpression( e, out );
                    out << "; }, " << parametersUsedInExpression(e) << " )";
                    first = false;
                }
                out << "], t );" << endl;
                out << "for( var i = 0; i < t." << idInstance << ".domNodes.length; ++i ) " << finalStatement.arg( "t." + idInstance + ".domNodes[i]") << endl;
                out << tmp << ".onChange.push( function() { t." << idInstance << " = t.processTemplateChange( t." << idInstance << ", this.evaluate() ); } );" << endl;
            }
        }
        else if ( dynamic_cast<ComponentCall*>(p) )
        {
            ComponentCall* c = dynamic_cast<ComponentCall*>(p);            
            QString idCall = c->data()["ident"];
            int i = 0;
            foreach( HtmlAttribute* a, c->attributeList()->attributes() )
            {
                Node* n = c->memberForAttribute(i++);
                Q_ASSERT(n);
                if ( dynamic_cast<Property*>(n) )
                {
                    Property* p = dynamic_cast<Property*>(n);
                    if ( a->expression() )
                    {
                        QString idExpr = nextIdent();
                        out << "var " << idExpr << " = new wala.Expression(t, function() { return ";
                        generateExpression( a->expression(), out );
                        out << " }, " << parametersUsedInExpression(a->expression()) << " );" << endl;
                        out << "t." << idCall << ".set_" << p->name() << "(" << idExpr << ");" << endl;
                    }
                    else
                        out << "t." << idCall << ".set_" << p->name() << "(" << stringify(a->value()) << ");" << endl;
                }
                else if ( dynamic_cast<MemberTemplate*>(n) )
                {
                    MemberTemplate* p = dynamic_cast<MemberTemplate*>(n);
                    if ( !a->expression() )
                    {
                        ErrorLog::error(a->location(), "You can only pass a template or an expression as value for the attribute " + a->name());
                        return;
                    }
                    QString idExpr = nextIdent();
                    out << "var " << idExpr << " = new wala.Expression(t, function() { return ";
                    generateExpression( a->expression(), out );
                    out << " }, " << parametersUsedInExpression(a->expression()) << " );" << endl;
                    out << "t." << idCall << ".set_" << p->name() << "(" << idExpr << ");" << endl;
                }
                else if ( dynamic_cast<MemberEvent*>(n) )
                {
                    MemberEvent* e = dynamic_cast<MemberEvent*>(n);
                    if ( a->expression() )
                    {
                        QString idExpr = nextIdent();
                        out << "var " << idExpr << " = new wala.Handler(t, function() { ";
                        generateExpression( a->expression(), out );
                        out << " } );" << endl;
                        out << "t." << idCall << "." << e->name() << "_event.addListener(" << idExpr << ".evaluate, " << idExpr << ");" << endl;
                    }
                    else
                    {
                        out << "t." << idCall << "." << e->name() << "_event.addListener(" << a->value() << ",t." << idCall << ");" << endl;
                    }
                }
                else
                    Q_ASSERT(false);
            }
            out << "t." << idCall << ".__nodes = t." << idCall << ".__ctor();" << endl;
            out << "for( var i = 0; i < t." << idCall << ".__nodes.length; ++i ) " << finalStatement.arg( "t." + idCall + ".__nodes[i]") << endl;
        }
        else if ( dynamic_cast<Expression*>(p) )
        {
            Expression* e = dynamic_cast<Expression*>(p);
            QString idNode = nextIdent();
            e->data()["ident"] = idNode;
            QString idExpr = nextIdent();
            QTextStream out2( new QString() );
            generateExpression( e->expression(), out2 );
            out << "var " << idExpr << " = new wala.Expression(t, function() { return " << *(out2.string()) << "; }, " << parametersUsedInExpression(e) << ");" << endl;
            out << "t." << idNode << " = document.createTextNode(" << idExpr << ".evaluate() );" << endl;
            out << idExpr << ".onChange.push( function() { t." << idNode << ".data = this.evaluate(); } );" << endl;
            out << finalStatement.arg( "t." + idNode ) << endl;
        }
        
        p = p->nextSibling();
    }
}

void JSBackend::generateHtmlBody_Pass3(Body* body, QTextStream& out)
{
    Node* p = body->firstChild();
    while( p )
    {
        if ( dynamic_cast<HtmlElement*>(p) )
        {
            HtmlElement* element = dynamic_cast<HtmlElement*>(p);
//            QString elementIdent = element->data()["ident"];
//            if ( removeChild )
//            {
//                if ( body->lastChild() == p )
//                    out << "next = t." << elementIdent << ".nextSibling;" << endl;
//                out << "if ( r ) { t." << elementIdent << ".parentNode.removeChild(t." << elementIdent << "); delete t." << elementIdent << "; }" << endl;
//            }
            generateHtmlBody_Pass3( element->body(), out );
        }
        else if ( dynamic_cast<TextNode*>(p) )
        {
//            TextNode* t = dynamic_cast<TextNode*>(p);
//            QString id = t->data()["ident"];
//            if ( removeChild )
//            {
//                if ( body->lastChild() == p )
//                    out << "next = t." << id << ".nextSibling;" << endl;
//                out << "if ( r ) { t." << id << ".parentNode.removeChild(t." << id << "); delete t." << id << "; }" << endl;
//            }
        }
        else if ( dynamic_cast<HtmlIf*>(p) )
        {
            HtmlIf* f = dynamic_cast<HtmlIf*>(p);
            QString id = f->data()["ident"];
//            if ( removeChild )
//            {
//                if ( body->lastChild() == p )
//                    out << "next = t.destructIf(t." << id << ", r);" << endl;
//                else
//                    out << "t.destructIf(t." << id << ", r);" << endl;
//            }
//            else
//                out << "t.destructIf(t." << id << ", false);" << endl;
            out << "t.destructIf(t." << id << ");" << endl;
        }
        else if ( dynamic_cast<HtmlForeach*>(p) )
        {
            HtmlForeach* f = dynamic_cast<HtmlForeach*>(p);
            QString id = f->data()["ident"];
//            if ( removeChild )
//            {
//                if ( body->lastChild() == p )
//                    out << "next = t.destructForeach(t." << id << ", r);" << endl;
//                else
//                    out << "t.destructForeach(t." << id << ", r);" << endl;
//            }
//            else
//                out << "t.destructForeach(t." << id << ", false);" << endl;
            out << "t.destructForeach(t." << id << ");" << endl;
        }
        else if ( dynamic_cast<TemplateCall*>(p) )
        {
            TemplateCall* c = dynamic_cast<TemplateCall*>(p);
            QString id = c->data()["ident"];
//            if ( removeChild )
//            {
//                if ( body->lastChild() == p )
//                    out << "next = t." << id << ".factory.dtor(t." << id << ", r);" << endl;
//                else
//                    out << "t." << id << ".factory.dtor(t." << id << ", r);" << endl;
//            }
//            else
//                out << "t." << id << ".factory.dtor(t." << id << ", false);" << endl;
            out << "t." << id << ".dtor();" << endl;
        }
        else if ( dynamic_cast<ComponentCall*>(p) )
        {
            ComponentCall* c = dynamic_cast<ComponentCall*>(p);
            QString idCall = c->data()["ident"];
//            if ( removeChild )
//            {
//                if ( body->lastChild() == p )
//                    out << "next = t." << idCall << ".__nodes[t." << idCall << ".__nodes.length-1].nextSibling;" << endl;
//                out << "t." << idCall << ".__dtor(r);" << endl;
//            }
//            else
//                out << "t." << idCall << ".__dtor(false);" << endl;
            out << "t." << idCall << ".__dtor();" << endl;
        }
        else if ( dynamic_cast<Expression*>(p) )
        {
//            Expression* e = dynamic_cast<Expression*>(p);
//            QString id = e->data()["ident"];
//            if ( removeChild )
//            {
//                if ( body->lastChild() == p )
//                    out << "next = t." << id << ".nextSibling;" << endl;
//                out << "if ( r ) { t." << id << ".parentNode.removeChild(t." << id << "); delete t." << id << "; }" << endl;
//            }
        }
        p = p->nextSibling();
    }
}

void JSBackend::generateHtmlBody_Pass4(Body* body, QTextStream& out)
{
    Node* p = body->firstChild();
    while( p )
    {
        if ( dynamic_cast<HtmlElement*>(p) )
        {
            HtmlElement* element = dynamic_cast<HtmlElement*>(p);
            QString elementIdent = element->data()["ident"];
            out << "nodes.push( t." << elementIdent << ");" << endl;
        }
        else if ( dynamic_cast<TextNode*>(p) )
        {
            TextNode* t = dynamic_cast<TextNode*>(p);
            QString id = t->data()["ident"];
            out << "nodes.push( t." << id << ");" << endl;
        }
        else if ( dynamic_cast<HtmlIf*>(p) )
        {
            HtmlIf* f = dynamic_cast<HtmlIf*>(p);
            QString id = f->data()["ident"];
            out << "t.allNodesIf(t." << id << ", nodes);" << endl;
        }
        else if ( dynamic_cast<HtmlForeach*>(p) )
        {
            HtmlForeach* f = dynamic_cast<HtmlForeach*>(p);
            QString id = f->data()["ident"];
            out << "t.allNodesForeach(t." << id << ", nodes);" << endl;
        }
        else if ( dynamic_cast<TemplateCall*>(p) )
        {
            TemplateCall* c = dynamic_cast<TemplateCall*>(p);
            QString id = c->data()["ident"];
            out << "t." << id << ".factory.allNodes(t." << id << ", nodes);" << endl;
        }
        else if ( dynamic_cast<ComponentCall*>(p) )
        {
            ComponentCall* c = dynamic_cast<ComponentCall*>(p);
            QString idCall = c->data()["ident"];
            out << "for( var i = 0; i < t." << idCall << ".__nodes.length; ++i ) nodes.push( t." << idCall << ".__nodes[i] );" << endl;
        }
        else if ( dynamic_cast<Expression*>(p) )
        {
            Expression* e = dynamic_cast<Expression*>(p);
            QString id = e->data()["ident"];
            out << "nodes.push( t." << id << ");" << endl;
        }
        p = p->nextSibling();
    }
}

void JSBackend::generateHtmlElement_Pass1(HtmlElement* element, QTextStream& out)
{
    QString ident = nextIdent();
    element->data()["ident"] = ident;
    out << "t." << ident << " = document.createElement(\"" << element->tag() << "\");" << endl;

    generateHtmlBody_Pass1(element->body(), out );
}

void JSBackend::generateHtmlElement_Pass2(HtmlElement* element, QTextStream& out)
{
    QString ident = element->data()["ident"];

    foreach( HtmlAttribute* a, element->attributeList()->attributes() )
    {
        QString jsname = a->name();
        if ( jsname == "class" )
            jsname = "className";

        if ( a->expression() )
        {
            if ( a->name().mid(0,6) == "style." )
            {                                
                QString idExpr = nextIdent();
                QTextStream out2( new QString() );
                generateExpression( a->expression(), out2 );
                out << "var " << idExpr << " = new wala.Expression(t, function() { return " << *(out2.string()) << "; }, " << parametersUsedInExpression(a->expression()) << ");" << endl;
                out << idExpr << ".onChange.push( function() { t." << ident << ".style." << a->name().mid(6) << " = this.evaluate(); } );" << endl;
                out << "t." << ident << ".style." << a->name().mid(6) << " = " << idExpr << ".evaluate();" << endl;
            }
            else if ( jsname.mid(0,2) == "on" )
            {
                QString idExpr = nextIdent();
                out << "var " << idExpr << " = new wala.Handler(t, function() { ";
                generateExpression( a->expression(), out );
                out << " } );" << endl;
                out << "t." << ident << "." << jsname << " = function() { " << idExpr << ".evaluate(); }" << endl;
            }
            else
            {
                QString idExpr = nextIdent();
                QTextStream out2( new QString() );
                generateExpression( a->expression(), out2 );
                out << "var " << idExpr << " = new wala.Expression(t, function() { return " << *(out2.string()) << "; }, " << parametersUsedInExpression(a->expression()) << ");" << endl;
                out << idExpr << ".onChange.push( function() { t." << ident << "." << a->name() << " = this.evaluate(); } );" << endl;
                out << "t." << ident << "." << a->name() << " = " << idExpr << ".evaluate();" << endl;
            }
        }
        else
        {
            if ( jsname == "style" )
            {
                QStringList styles = a->value().split(';');
                foreach( QString expr, styles )
                {
                    QString tmp = expr.trimmed();
                    if ( tmp.isEmpty() )
                        continue;
                    int index = expr.indexOf(':');
                    if ( index == -1 )
                    {
                        ErrorLog::error( a->location(), "Malformed CSS expression, missing :");
                        continue;
                    }
                    QString key = jsCSSName( a, tmp.left(index).trimmed() );
                    QString value = tmp.mid(index+1).trimmed();
                    out << "t." << ident << ".style." << key << " = " << stringify( value ) << ";" << endl;
                }
            }
            else if ( jsname.mid(0,2) == "on" )
                out << "t." << ident << "." << jsname << " = function() {" << a->value() << "; };" << endl;
            else
                out << "t." << ident << "." << jsname << " = " << stringify( a->value() ) << ";" << endl;
        }
    }

    generateHtmlBody_Pass2(element->body(), out, "t." + ident + ".appendChild(%1);" );
}

void JSBackend::generateExpression( Node* expr, QTextStream& out )
{
    if ( dynamic_cast<Expression*>(expr) )
    {
        generateExpression( dynamic_cast<Expression*>(expr)->expression(), out );
    }
    else if ( dynamic_cast<Constant*>(expr) )
    {
        Constant* c = dynamic_cast<Constant*>(expr);
        switch( c->kind() )
        {
            case Constant::Null:
                out << "null";
                break;
            case Constant::False:
                out << "false";
                break;
            case Constant::True:
                out << "true";
                break;
            case Constant::VariableIdentifier:
                if ( dynamic_cast<Var*>(c->resolvedNode()) )
                {
                    Var* v = dynamic_cast<Var*>(c->resolvedNode());
                    if ( v->isConstant() )
                        out << "wala.getVarAndListen(" << stringify(v->name()) << ", this )";
                    else
                        out << "wala.getVar(" << stringify(v->name()) << ").evaluate()";
                }
                else if ( dynamic_cast<Parameter*>(c->resolvedNode()) )
                {
                    Parameter* p = dynamic_cast<Parameter*>(c->resolvedNode());
                    if ( p->isIndex() )
                        out << "t.getIndexAndListen( this.setDirty, this )";
                    else if ( p->data()["noexpression"] == "true" )
                        out << p->data()["ident"];
                    else
                        out << p->data()["ident"] << ".evaluate()";
                }
                else if ( dynamic_cast<Template*>(c->resolvedNode()) )
                {
                    Template* t = dynamic_cast<Template*>(c->resolvedNode());
                    // TODO: Register for the case that the member templates changes
                    out << t->data()["ident"];
                }
                else if ( dynamic_cast<MemberTemplate*>(c->resolvedNode()) )
                {
                    MemberTemplate* t = dynamic_cast<MemberTemplate*>(c->resolvedNode());
                    out << "t.component.get_" << t->name() << "().evaluate()";
                }
                else if ( dynamic_cast<MemberFunction*>(c->resolvedNode()) )
                {
                    MemberFunction* t = dynamic_cast<MemberFunction*>(c->resolvedNode());
                    out << "t.component.call_" << t->name();
                }
                else if ( dynamic_cast<Property*>(c->resolvedNode()) )
                {
                    Property* p = dynamic_cast<Property*>(c->resolvedNode());
                    out << "t.component.get_" << p->name() << "()";
                }
                else if ( dynamic_cast<ComponentCall*>(c->resolvedNode()) )
                {
                    ComponentCall* call = dynamic_cast<ComponentCall*>(c->resolvedNode());
                    out << "t." << call->data()["ident"];
                }
                else
                    ErrorLog::error( expr->location(), "The identifier " + c->stringValue() + " does not represent an entity that can be used in an expression." );
                break;
            case Constant::Int:
                out << c->intValue();
                break;
            case Constant::Float:
                out << c->floatValue();
                break;
            case Constant::String:
                out << stringify(c->stringValue());
                break;
            case Constant::LambdaParameter:
                out << "param";
                break;
            case Constant::TagIdentifier:
            case Constant::TagListIdentifier:
                ErrorLog::error( expr->location(), "Tag names (here '" + c->stringValue() + "') cannot be used in an arithmetic expression or as start element of a path query");
                break;
            }
    }
    else if ( dynamic_cast<CallOperator*>(expr) )
    {
        CallOperator* op = dynamic_cast<CallOperator*>(expr);
        if ( op->identifier() == "len" )
        {
            out << op->resolvedFunction()->jsName() << "(";
            generateExpression( op->callArgs()->expressions()[0], out );
            out << ")";
        }
        else if ( dynamic_cast<MemberFunction*>(op->resolvedFunction()) )
        {
            out << "t.component." << op->resolvedFunction()->jsName() << "(";
            bool first = false;
            foreach( Expression* e, op->callArgs()->expressions() )
            {
                if ( !first )
                    out << ",";
                first = false;
                generateExpression(e, out );
            }
            out << ")";
        }
        else
        {
            out << op->resolvedFunction()->jsName() << ".call(this";
            foreach( Expression* e, op->callArgs()->expressions() )
            {
                out << ",";
                generateExpression(e, out );
            }
            out << ")";
        }
    }
    else if ( dynamic_cast<DotCallOperator*>(expr) )
    {
        DotCallOperator* op = dynamic_cast<DotCallOperator*>(expr);
        generateExpression( op->object(), out );
        out << "." << op->identifier() << "(";
        bool first = true;
        foreach( Expression* e, op->callArgs()->expressions() )
        {
            if ( !first )
                out << ",";
            generateExpression(e, out );
            first = false;
        }
        out << ")";
    }
    else if ( dynamic_cast<PathOperator*>(expr) )
    {
        PathOperator* op = dynamic_cast<PathOperator*>(expr);
        if ( op->type().isList() )
            out << generatePath(op, m_out) << ".call(this, null, 0, null)";
        else
            out << generatePath(op, m_out) << ".call(this, null, 0)";
    }
    else if ( dynamic_cast<DotOperator*>(expr) )
    {        
        DotOperator* op = dynamic_cast<DotOperator*>(expr);                
        out << "wala.getValueAndListen(";
        generateExpression( op->argument(), out );        
        out << "," << stringify(op->identifier()) << ",this)";
    }
    else if ( dynamic_cast<UnaryOperator*>(expr) )
    {
        UnaryOperator* op = dynamic_cast<UnaryOperator*>(expr);
        switch( op->operatorKind() )
        {
            case Operator::Neg:
                out << "-";
                generateExpression( op->argument(), out );
                break;
            case Operator::Not:
                out << "!";
                generateExpression( op->argument(), out );
                break;
            default:
                Q_ASSERT(false);
        }
    }
    else if ( dynamic_cast<BinaryOperator*>(expr) )
    {
        BinaryOperator* op = dynamic_cast<BinaryOperator*>(expr);
        switch( op->operatorKind() )
        {
            case Operator::Add:
                generateExpression( op->firstArgument(), out );
                out << "+";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::Sub:
                generateExpression( op->firstArgument(), out );
                out << "-";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::Mul:
                generateExpression( op->firstArgument(), out );
                out << "*";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::Less:
                generateExpression( op->firstArgument(), out );
                out << "<";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::Greater:
                generateExpression( op->firstArgument(), out );
                out << ">";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::Equal:
                generateExpression( op->firstArgument(), out );
                out << "==";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::NotEqual:
                generateExpression( op->firstArgument(), out );
                out << "!=";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::GreaterOrEqual:
                generateExpression( op->firstArgument(), out );
                out << ">=";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::LessOrEqual:
                generateExpression( op->firstArgument(), out );
                out << "<=";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::And:
                generateExpression( op->firstArgument(), out );
                out << "&&";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::Or:
                generateExpression( op->firstArgument(), out );
                out << "||";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::Div:
                generateExpression( op->firstArgument(), out );
                out << "/";
                generateExpression( op->secondArgument(), out );
                break;
            case Operator::Power:
                out << "Math.pow(";
                generateExpression( op->firstArgument(), out );
                out << ",";
                generateExpression( op->secondArgument(), out );
                out << ")";
                break;
            case Operator::Metric:
                qDebug("Not implemented yet");
                break;
            case Operator::Index:
                if ( dynamic_cast<RangeOperator*>( op->secondArgument() ) )
                {
                    RangeOperator* r = dynamic_cast<RangeOperator*>( op->secondArgument() );
                    if ( r->leftBoundary() && r->rightBoundary() )
                    {
                        out << "wala.range(";
                        generateExpression( op->firstArgument(), out );
                        out << ",";
                        generateExpression( r->leftBoundary(), out );
                        out << ",";
                        generateExpression( r->rightBoundary(), out );
                        out << ")";
                    }
                    else if ( r->leftBoundary() && !r->rightBoundary() )
                    {
                        out << "wala.rangeMid(";
                        generateExpression( op->firstArgument(), out );
                        out << ",";
                        generateExpression( r->leftBoundary(), out );
                        out << ")";
                    }
                    else if ( !r->leftBoundary() && r->rightBoundary() )
                    {
                        out << "wala.rangeRight(";
                        generateExpression( op->firstArgument(), out );
                        out << ",";
                        generateExpression( r->rightBoundary(), out );
                        out << ")";
                    }
                    else
                        Q_ASSERT(false);
                }
                else
                {
                    out << "wala.index(";
                    generateExpression( op->firstArgument(), out );
                    out << ",";
                    generateExpression( op->secondArgument(), out );
                    out << ")";
                }
                break;
            case Operator::Filter:
                out << "wala.filter(";
                generateExpression( op->firstArgument(), out );
                out << ", function(param) { return ";
                generateExpression( op->secondArgument(), out );
                out << "; })";
                break;
            case Operator::Call:
            case Operator::Constant:
            case Operator::Range:
            case Operator::Path:
            case Operator::Dot:
            case Operator::Neg:
            case Operator::Not:
            case Operator::DotCall:
            case Operator::If:
                Q_ASSERT(false);
                break;
        }
    }
    else if ( dynamic_cast<IfOperator*>(expr) )
    {
        IfOperator* i = dynamic_cast<IfOperator*>(expr);
        out << "(";
        generateExpression( i->condition(), out );
        out << ") ? (";
        generateExpression( i->ifClause(), out );
        out << ") : (";
        generateExpression( i->elseClause(), out );
        out << ")";
    }
    else
    {
        // TODO
    }
}

QString JSBackend::generatePath( PathOperator* op, QTextStream& out )
{
    QString funcIdent = nextIdent();
    if ( op->type().kind() == Type::Scalar )
        out << "function " << funcIdent << "(p,level)" << endl << "{" << endl;
    else
        out << "function " << funcIdent << "(p,level,result)" << endl << "{" << endl;
    // This is required because some of the generated code expects the template instance in a variable named 't'.
    out << "var t = this.templateInstance;" << endl;
    int i = 0;
    QList<Node*> expressions = op->expressions();
    foreach( Node* expr, expressions )
    {
        out << "if ( level == " << i << " ) {" << endl;

        if ( i == 0 )
        {
            // The expression itself is a scalar. The Path can still return a list or a scalar.
            if ( expr->type().kind() == Type::Scalar )
            {
                if ( op->type().kind() == Type::List )
                    out << "result = [];" << endl;
                out << "var p2 = ";
                generateExpression( expr, out );
                out << ";" << endl;
                if ( op->type().kind() == Type::List )
                    out << "if ( !p2 ) return [];" << endl;
                else
                    out << "if ( !p2 ) return null;" << endl;
                out << "if ( p2.rootNode ) p2.rootNode().getEvent(\"change\").addExprListener( this );" << endl;
                if ( op->type().kind() == Type::List )
                {
                    out << funcIdent << ".call(this, p2, 1, result);" << endl;
                    out << "return result;" << endl;
                }
                else
                    out << "return " << funcIdent << ".call(this, p2, 1);" << endl;
            }
            else // The expression is a list and therefore the path returns a list as well
            {
                out << "result = [];" << endl;
                out << "var p2 = ";
                generateExpression( expr, out );
                out << ";" << endl;
                out << "for( var i = 0; i < p2.length; ++i )" << endl << "{" << endl;
                out << "p2[i].rootNode().getEvent(\"change\").addExprListener( this );" << endl;
                out << funcIdent << ".call(this, p2[i], 1, result);" << endl;
                m_out << "}" << endl;
                out << "return result;" << endl;
            }
            m_out << "}" << endl;
            i++;
            continue;
        }

        out << "if ( p.rootNode ) p.rootNode().getEvent(\"change\").addExprListener( this );" << endl;

        if ( dynamic_cast<Constant*>(expr) )
        {
            Constant* c = dynamic_cast<Constant*>(expr);
            switch( c->kind() )
            {
            case Constant::TagListIdentifier:
                out << "var c = p.firstChild;" << endl;
                out << "while( c ) {" << endl;
                if ( i + 1 == expressions.count() )
                    out << "if ( c.type == \"" << c->stringValue() << "\" ) result.push(c);" << endl;
                else
                    out << "if ( c.type == \"" << c->stringValue() << "\" ) " << funcIdent << ".call(this, c, " << i + 1 << ", result );" << endl;
                out << "c = c.nextSibling;" << endl;
                out << "}" << endl;
                break;
            case Constant::TagIdentifier:
                out << "var c = p.firstChild;" << endl;
                out << "while( c ) {" << endl;
                // The last path element?
                if ( i + 1 == expressions.count() )
                {
                    if ( op->type().kind() == Type::Scalar )
                        out << "if ( c.type == \"" << c->stringValue() << "\" ) return c;" << endl;
                    else
                        out << "if ( c.type == \"" << c->stringValue() << "\" ) { result.push(c); return; }" << endl;
                }
                else
                {
                    if ( op->type().kind() == Type::Scalar )
                        out << "if ( c.type == \"" << c->stringValue() << "\" ) return " << funcIdent << ".call(this, c, " << i + 1 << ");" << endl;
                    else
                        out << "if ( c.type == \"" << c->stringValue() << "\" ) { " << funcIdent << ".call(this, c, " << i + 1 << ", result ); return; }" << endl;
                }
                out << "c = c.nextSibling;" << endl;
                out << "}" << endl;
                if ( op->type().kind() == Type::Scalar )
                    out << "return null;" << endl;
                break;
            default:
                ErrorLog::error(c->location(), "Cannot use constants or variables as path elements in the middle of a query path");
                break;
            }
        }
        else if ( dynamic_cast<CallOperator*>(expr) )
        {
            if ( expr->type().isScalar() )
            {
                CallOperator* cop = dynamic_cast<CallOperator*>(expr);
                if ( cop->callArgs()->count() + 1 != cop->resolvedFunction()->parameterList()->count() )
                    ErrorLog::error(cop->location(), "The function " + cop->resolvedFunction()->name() + " has no matching parameter list");
                if ( cop->resolvedFunction()->parameterList()->parameter(0)->type().kind() != Type::Scalar )
                    ErrorLog::error(cop->location(), "The first parameter of the function " + cop->resolvedFunction()->name() + " is not a scalar");
                out << "var item = " << cop->resolvedFunction()->jsName() << ".call(this, p";
                foreach( Expression* e, cop->callArgs()->expressions() )
                {
                    out << ",";
                    generateExpression(e, out );
                }
                out << ");" << endl;
                if ( i + 1 == expressions.count() )
                {
                    if ( op->type().isScalar() )
                        out << "return item;" << endl;
                    else
                        out << "result.push( item );" << endl;
                }
                else
                {
                    if ( op->type().isScalar() )
                        out << "return " << funcIdent << ".call(this, item, " << i + 1 << " );" << endl;
                    else
                        out << funcIdent << ".call(this, item, " << i + 1 << ", result );" << endl;
                }
            }
            else
            {
                out << "var lst = ";
                CallOperator* op = dynamic_cast<CallOperator*>(expr);
                out << op->resolvedFunction()->jsName() << ".call(this, p";
                foreach( Expression* e, op->callArgs()->expressions() )
                {
                    out << ",";
                    generateExpression(e, out );
                }
                out << ");" << endl;
                if ( i + 1 == expressions.count() )
                    out << "for( var i = 0; i < lst.length; ++i ) result.push( lst[i] );" << endl;
                else
                    out << "for( var i = 0; i < lst.length; ++i ) " << funcIdent << ".call(this, lst[i], " << i + 1 << ", result );" << endl;
            }
        }
        else
            ErrorLog::error(expr->location(), "This syntactic construct is not allowed as path element in the middle of a query path");

        i++;
        m_out << "}" << endl;
    }

    m_out << "}" << endl << endl;
    return funcIdent;
}

QSet<Parameter*> JSBackend::parametersUsed(Node* e)
{
    QSet<Parameter*> result;
    parametersUsed(e, result);
    return result;
}

void JSBackend::parametersUsed(Node* e, QSet<Parameter*>& lst)
{
    if ( dynamic_cast<Constant*>(e) )
    {
        Constant* c = dynamic_cast<Constant*>(e);
        if ( c->kind() == Constant::VariableIdentifier && dynamic_cast<Parameter*>( c->resolvedNode() ) )
            lst.insert( dynamic_cast<Parameter*>( c->resolvedNode() ) );
    }

    Node* p = e->firstChild();
    while( p )
    {
        parametersUsed(p, lst);
        p = p->nextSibling();
    }
}

QSet<Parameter*> JSBackend::parametersDeclared(Node* e)
{
    QSet<Parameter*> result;
    parametersDeclared(e, result);
    return result;
}

void JSBackend::parametersDeclared(Node* e, QSet<Parameter*>& lst)
{
    if ( dynamic_cast<Parameter*>(e) )
    {
        Parameter* p = dynamic_cast<Parameter*>(e);
        lst.insert( p );
    }

    Node* p = e->firstChild();
    while( p )
    {
        parametersDeclared(p, lst);
        p = p->nextSibling();
    }
}

QString JSBackend::parametersUsedInExpression(Node* e)
{
    QSet<QString> lst;
    parentExpressions(e, lst);

    QString result = "[";
    bool first = true;
    foreach( QString str, lst )
    {
        if ( !first )
            result += ",";
        result += str;
        first = false;
    }
    if ( first )
        result = "null";
    else
        result += "]";
    return result;
}

void JSBackend::parentExpressions(Node* e, QSet<QString>& result)
{
    if ( dynamic_cast<Constant*>(e) )
    {
        Constant* c = dynamic_cast<Constant*>(e);
        if ( c->kind() == Constant::VariableIdentifier && dynamic_cast<Parameter*>( c->resolvedNode() ) )
        {
            Parameter* para = dynamic_cast<Parameter*>( c->resolvedNode() );
            if ( para->data()["noexpression"].isNull() )
                result.insert(para->data()["ident"]);
        }
        else if ( c->kind() == Constant::VariableIdentifier && dynamic_cast<Property*>( c->resolvedNode() ) )
        {
            Property* p = dynamic_cast<Property*>( c->resolvedNode() );
            result.insert("t.component.expr_" + p->name());
        }
        else if ( c->kind() == Constant::VariableIdentifier && dynamic_cast<MemberTemplate*>( c->resolvedNode() ) )
        {
            MemberTemplate* p = dynamic_cast<MemberTemplate*>( c->resolvedNode() );
            result.insert("t.component.expr_" + p->name());
        }
        // TODO: Member variables and member functions
        else if ( c->kind() == Constant::VariableIdentifier && dynamic_cast<Var*>( c->resolvedNode() ) )
        {
            Var* v = dynamic_cast<Var*>( c->resolvedNode() );
            if ( !v->isConstant() )
                result.insert(v->data()["ident"]);
        }
    }

    Node* p = e->firstChild();
    while( p )
    {
        parentExpressions(p, result);
        p = p->nextSibling();
    }
}

void JSBackend::transformIf( HtmlIf* f )
{
    // Which parameters are required?
    ParameterList* params = new ParameterList( f->location() );
    QSet<Parameter*> paramsDecl = parametersDeclared(f->body());
    foreach( Parameter* p, parametersUsed(f->body()) )
    {
        if ( !paramsDecl.contains(p) )
        {
            Parameter* p2 = new Parameter( p->name(), p->type(), p->location() );
            if ( !p->data()["noexpression"].isNull() )
                p2->data()["noexpression"] = p->data()["noexpression"];
            params->appendChild( p2 );
        }
    }

    // Create a new template
    Template* t = new Template( nextIdent(), params, f->body(), f->location() );
    t->data()["ident"] = nextIdent();
    f->setBodyTemplate(t);
    t->resolveAll();

    generateTemplateBody(t);
}

void JSBackend::finish()
{
    m_out << *(m_mainOutDecl.string());
    m_out << *(m_mainOutDef.string());

    m_out << "var root = " << Parser::self()->mainTemplate()->data()["ident"] << ".createInstance( [], null );" << endl;
    m_out << "var body = document.getElementById(\"body\");" << endl;
    m_out << "for( var i = 0; i < root.domNodes.length; ++i ) body.insertBefore( root.domNodes[i], null );" << endl;

    m_out << "}" << endl << endl;

    m_out.flush();
    m_fileOut.close();
}

QString JSBackend::nextIdent()
{
    m_identCount++;
    return QString("x%1").arg(m_identCount);
}

QString JSBackend::stringify(const QString& str) const
{
    // TODO
    QString s(str);
    s.replace('"', "\\\"");
    s.replace('\n', "\\n");
    s.replace('\t', "\\t");
    s.replace('\f', "\\f");
    return "\"" + s + "\"";
}

QString JSBackend::jsCSSName( HtmlAttribute* a, const QString& name )
{
    QString result( name );

    int index;
    while( ( index = result.indexOf('-') ) != -1 )
    {
        if ( result.length() <= index + 1 )
        {
            ErrorLog::error( a->location(), "Malformed CSS expression, unexpected -");
            return result;
        }
        result = result.left(index) + result[index+1].toUpper() + result.mid(index+2);
    }
    return result;
}
